package com.dianba.commons.aop;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;

/**
 * 手机端日志输出
 * 
 * @author zhoucong
 *
 */
@Service
@Aspect
public class AppApiLogAop {
	private static boolean debug = true;
	private static final String EXECUTION = "execution(* com.dianba.userdomain.*.controller.*.*(..))";
	private final Log logger = LogFactory.getLog(this.getClass());
	private String requestPath = null; // 请求地址
	private ThreadLocal<Map<String, Object>> outputParamMap = new ThreadLocal<>(); // 存放输出结果
	private long startTimeMillis = 0; // 开始时间
	private long endTimeMillis = 0; // 结束时间
	private static final Map<String, String> APIS = new HashMap<>();

	@Before(EXECUTION)
	public void doBeforeInServiceLayer(JoinPoint joinPoint) {
		startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
	}

	@After(EXECUTION)
	public void doAfterInServiceLayer(JoinPoint joinPoint) {
		endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
		this.printOptLog();
	}

	@Around(EXECUTION)
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		// 开发和测试环境输出
		if (debug) {
			HttpServletRequest request = getRequest();
			requestPath = request.getRequestURL().toString(); // 获取请求地址
			// 执行完方法的返回值：调用proceed()方法，就会触发切入点方法执行
			Map<String, Object> R = new HashMap<String, Object>();
			outputParamMap.set(R);
			Object result = pjp.proceed();// result的值就是被拦截方法的返回值
			R.put("result", result);
			return result;
		} else {
			return pjp.proceed();
		}
	}

	private HttpServletRequest getRequest() {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		return request;
	}

	private void printOptLog() {
		if (debug) {
			StringBuilder sb = new StringBuilder();
			sb.append(requestPath).append("?");
			HttpServletRequest request = getRequest();
			Map<String, String[]> inputParamMap = request.getParameterMap();
			Enumeration<String> headerNames = request.getHeaderNames();
			try {
				while (headerNames.hasMoreElements()) {
					String headerName = (String) headerNames.nextElement();
					sb.append(headerName).append("=");
					sb.append(request.getHeader(headerName)).append("\n");
				}
			} catch (Exception e) {
			}

			try {
				for (Object str : inputParamMap.keySet()) {
					String s = ((String[]) inputParamMap.get(str))[0];
					sb.append(str).append("=").append(s).append("&");
				}
				APIS.put(requestPath, sb.toString());

				writeApi(request.getServletPath());
				logger.info("\n ===action start=== \n url:" + requestPath + " \n fullurl:" + sb + "\n exetime:"
						+ (endTimeMillis - startTimeMillis) + "ms" + "\n param:"
						+ JSONObject.toJSONString(inputParamMap) + "\n result:" + outputParamMap.get().get("result")
						+ "\n ===action end===");
			} catch (Exception e) {
			}

			outputParamMap.remove();
		}
	}

	private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0);

	public static void main(String[] args) {
		System.out.println(10 % 100);
	}

	private static void writeApi(String path) {
		PrintWriter printWriter = null;
		int i = ATOMIC_INTEGER.incrementAndGet();
		if (i % 3 == 0) {
			synchronized (ATOMIC_INTEGER) {
				try {
					File file = new File(new File(path).getParent(), "apis.log");
					FileOutputStream outputStream = new FileOutputStream(file);
					printWriter = new PrintWriter(outputStream);
					for (String api : APIS.keySet()) {
						printWriter.println(api);
					}
					printWriter.println("################################");
					printWriter.println("################################");
					printWriter.println("################################");
					for (String api : APIS.keySet()) {
						printWriter.println(APIS.get(api));
					}
					printWriter.close();

				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					try {
						if (printWriter != null) {
							printWriter.close();
						}
					} catch (Exception e2) {
						// TODO: handle exception
					}
				}
			}
		}
	}
}